/*
 *	Perlin Production Co. Ltd. September 2012 (c).
 *			pallib.c
 *		
 */
#include "stdio.h"
#include "paramlib.h"
#include "WinGDI.h"

#define _DEBUG	0

#define NCOLORS	0x10
 
RGB*	ClrV06(_rgb, _rgb888)
RGB*	_rgb;
RGB*	_rgb888;
{
	_rgb->rgbReserved = _rgb888	? Euc233(_rgb, _rgb888)
					: Clr233(_rgb);
	return _rgb;
}



/* DUPLICATE COLOR RESOLVERS */

RGB*	CRLumo(_rgb1, _rgb2, _rgb888) /* resolve duplicate colors by luminosity */
RGB*	_rgb1;
RGB*	_rgb2;
RGB*	_rgb888;
{
	unsigned	lumo1,lumo2;
	RGB		*rgb;	/* color to modify */
	char		clrDup;

	clrDup	= _rgb1->rgbReserved;
	lumo1	= Lumo(_rgb1);
	lumo2	= Lumo(_rgb2);
	
#if _DEBUG
	PutRGB(_rgb1,"_rgb1");
	PutRGB(_rgb2,"_rgb2");
	printf("Lumo1:%03u, Lumo2:%03u\n",lumo1,lumo2);
#endif	
	if (lumo1 == lumo2) return CRCClr(_rgb1, _rgb2, _rgb888);
	
	if (clrDup > 0x80) /* will decrease one with LESS lumo, but not 0 */
	{
		if (!lumo1) rgb = _rgb2;
		else if (!lumo2) rgb = _rgb1;
		else rgb = (lumo1 < lumo2) ? _rgb1 : _rgb2;
		DcrRGB(rgb);
	}
	else /* will increase one with MORE lumo, but not 0xFF */
	{
		if (lumo1 == 0xFF) rgb = _rgb2;
		else if (lumo2 == 0xFF) rgb = _rgb1;
		else rgb = (lumo1 > lumo2) ? _rgb1 : _rgb2;
		InrRGB(rgb);
	}
	return ClrV06(rgb, _rgb888);
}










RGB*	CRCClr(_rgb1, _rgb2, _rgb888) /* resolve duplicate by closest color */
RGB*	_rgb1;
RGB*	_rgb2;
RGB*	_rgb888;
{
	RGB		rgb233;
	RGB		*rgb;
	unsigned	d1,d2;
	
	if (CPIRGB(_rgb2,0)) rgb = InrRGB(_rgb1);
	else
	if (CPIRGB(_rgb1,0)) rgb = InrRGB(_rgb2);
	else
	{
	/* calculating distances between 233 and 888 components in 888 CS */
		CSELin(&rgb233, _rgb1->rgbReserved); /* 233 to 888 */
		d1	= EDist(rgb233, _rgb1);
		CSELin(&rgb233, _rgb2->rgbReserved); /* 233 to 888 */
		d2	= EDist(rgb233, _rgb2);
		rgb	= (d1 > d2) ? _rgb1 : _rgb2;
		if (Lumo(rgb) > 64) InrRGB(rgb);
		else DcrRGB(rgb);
	}
	return ClrV06(rgb, _rgb888);
}



/* Finds duplicate color in palette, or returns 0 */

RGB* DupClr(_rgb, _index, _verbose)
RGB	*_rgb;
int	_index;
int	_verbose;
{
	int	i;
	RGB	*rgb;
	RGB	*rgb233;
	char	clr233;
	
	rgb233	= &_rgb[_index];
	clr233	= rgb233->rgbReserved;
	
	for (i=0, rgb=_rgb; i < NCOLORS; ++i, ++rgb)
	{
		if ((i != _index) && clr233 == rgb->rgbReserved)
		{
			/* check that color components differ */
			if (!IsERGB(rgb233, rgb)) return rgb;
		}
	}
	return 0;
}




	
PalUni(_rgb, _rgb888, _resolve, _attempts, _verbose) /* make unique colors */
RGB	*_rgb;
RGB	*_rgb888;
RGB*	(*_resolve)();	/* pointer to duplicate color resolver */
int	_attempts;
int	_verbose;
{
 int	i,a;
 char	clr;
 RGB	*rgb;
	
 if (_verbose) printf("Checking duplicate colors");
 if (_verbose == VERBMAX) printf(", %d attempts", _attempts);
 printf("\n");
 
 a = _resolve ? 0 : _attempts;
 
 for (i=0; i < NCOLORS; ++i)
 {
	if (rgb = DupClr(_rgb, i, _verbose))
	{
		clr = rgb->rgbReserved;
		if ((_verbose && !_resolve) || (_verbose == VERBMAX))
		{
			printf	("Duplicate color[%02d]=%03u", i, clr);
			PutRGB(rgb,0);
		}
		
		if (_resolve)
		{
			if (a == _attempts)
			{
				if (_verbose) printf("\007\nUNABLE TO RESOLVE ALL DUPLICATES:\n");
				_resolve = 0;
				i=-1;
			}
			else
			{
				++a;
				rgb = (*_resolve)(&_rgb[i], rgb, _rgb888);
				if (rgb)
				{
				 if (_verbose == VERBMAX)
				 {
					printf	(" resolver attempt %02d yields %03u", a, rgb->rgbReserved);
					PutRGB(rgb, 0);
			 	 }
				 i=-1;
				}
				else
				{
				 if (_verbose == VERBMAX)
				 	printf("resolver attempt %d failed\n",a);
				}
			}
		}
	}
 }	
}







/*
Plane flip color conversion

0	0000	0000	0
1	0001	1000	8
2	0010	0100	4
3	0011	1100	c
4	0100	0010	2
5	0101	1010	a
6	0110	0110	6
7	0111	1110	e
8	1000	0001	1
9	1001	1001	9
a	1010	0101	5
b	1011	1101	d
c	1100	0011	3
d	1101	1011	b
e	1110	0111	7
f	1111	1111	f
*/

char	ClFlip(_i)
char	_i;
{
	return 	( ((_i & 1) << 3)
		| ((_i & 2) << 1)
		| ((_i & 4) >> 1)
		| ((_i & 8) >> 3)
		);
}



PalFli(_rgb)
RGB*	_rgb;
{
	int	i,j;
	RGB	*rgb;
	RGB	tmp;
	int	flip[NCOLORS];
		
	for (i=0; i < NCOLORS; ++i) flip[i] = ~0;
	
	for (i=0; i < NCOLORS; ++i)
	{
		j = ClFlip(i);
		if (flip[i] && flip[j])
		{
			CpyRGB(&tmp	, &_rgb[j]);
			CpyRGB(&_rgb[j]	, &_rgb[i]);
			CpyRGB(&_rgb[i]	, &tmp);
			
			flip[i] = flip[j] = 0;
		}
	}
}




PalSav	(_rgb, _rgbBMP, _fname, _verbose)
RGB	*_rgb;
RGB	*_rgbBMP;	/* Converted bitmap file palette in 888 */
char	*_fname;
int	_verbose;
{
	FILE	*fd;
	int	i;

	if (!(fd = fopen(_fname,"w",128))) { perror(_fname); exit(1); }
	if (_verbose==VERBMAX) printf("Saving palette for Vector-06c to %s\n", _fname);
	
	fprintf(fd,"; %s file for Vector-06c\n", _fname);
	fprintf(fd,";\tColor\t\tSource\n;\t\t   L\t  B     G     R\n");
	
	for (i=0; i < NCOLORS; ++i, ++_rgb, ++_rgbBMP)
	{
		fprintf	( fd
			,"DB\t%03u\t; %03u\t%03u , %03u , %03u\n"
			, _rgb->rgbReserved
			, Lumo(_rgbBMP)
			, _rgbBMP->rgbBlue
			, _rgbBMP->rgbGreen
			, _rgbBMP->rgbRed
			);
	}
	
	if (fclose(fd)) { perror(_fname); exit(1); }
	else if (_verbose) printf("Palette saved to %s\n", _fname);
}




PalWrt(_fname, _rgbBMP, _rgb888, _resolve, _attempts, _verbose)
char		*_fname;
RGB		*_rgbBMP;	/* Converted bitmap file palette in 888 */
RGB		*_rgb888;	/* Vector-06c palette in 888 colorspace */
RGB*		(*_resolve)();	/* pointer to duplicate color resolver  */
int		_attempts;
int		_verbose;
{
	RGB	*rgbBMP;		/* Points 888 components */
	RGB	*rgb;			/* Destination */
	RGB	rgbV06[NCOLORS];	/* Vector-06c palette */
	int	i;
	
	for	( i=0, rgbBMP = _rgbBMP, rgb = rgbV06
		; i < NCOLORS
		; ++i, ++rgbBMP, ++rgb
		)
	{
		if (_verbose == VERBMAX) putchar('.');

		CpyRGB(rgb, rgbBMP);
		ClrV06(rgb, _rgb888); /* rgb->rgbReserved = EDist(_rgb888) */
	}
	PalUni	(rgbV06, _rgb888, _resolve, _attempts, _verbose);
	PalSav	(rgbV06, _rgbBMP, _fname, _verbose);
}
